﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CCPnuts.ISkyDiskFileSystem.Interfaces;
using HgCo.WindowsLive.SkyDrive;
using CCPnuts.Pack;
using System.Threading;
using CCPnuts.Base;

namespace SkyDiskFileSystem
{
    internal abstract class SkyElementContainer : SkyElement, I_SkyElementContainer, IUpdatable
    {
        protected SkyDriveWebClient Client { get; set; }

        internal SkyElementContainer(PackedInfo packedInfo, SkyDriveWebClient client, I_SkyDirectory parent, WebFolderInfo item)
            : base(packedInfo, parent, item) { Client = client; }

        #region I_SkyElementContainer Members

        public I_Uploader UploadFile(string path)
        {
            throw new NotImplementedException();
        }

        public void Delete(I_SkyElement element)
        {
            throw new NotImplementedException();
        }

        public void DeleteFile(string fileName)
        {
            throw new NotImplementedException();
        }

        public void DeleteDir(string dirName)
        {
            throw new NotImplementedException();
        }

        public void CreateDir(string dirName)
        {
            throw new NotImplementedException();
        }

        public I_SkyDirectory this[string path]
        {
            get { throw new NotImplementedException(); }
        }

        public I_SkyFile this[string path, string fileName]
        {
            get { throw new NotImplementedException(); }
        }

        public I_SkyDirectory GetDir(string dirName)
        {
            throw new NotImplementedException();
        }

        public bool HasDir(string dirName)
        {
            throw new NotImplementedException();
        }

        public I_SkyFile GetFile(string fileName)
        {
            throw new NotImplementedException();
        }

        public bool HasFile(string fileName)
        {
            throw new NotImplementedException();
        }

        public bool UploadDirectory(string dirpath)
        {
            throw new NotImplementedException();
        }

        #endregion

        internal SkyElementCollection _Children { get; set; }

        public I_SkyElementCollection Children
        {
            get
            {
                Monitor.Enter(this);

                if (_Children == null)
                {
                    _Children = new SkyElementCollection(Client, null, GetItems());
                }
                Monitor.Exit(this);
                return _Children;
            }
        }

        /// <summary>
        /// Try to get the children. If this is already in Monitor, return immediately.
        /// </summary>
        internal void TryGetChildren()
        {
            if (Monitor.TryEnter(this))
            {
                BeginGetItems(ia =>
                {
                    _Children = new SkyElementCollection(Client, null, EndGetItems(ia));
                    AutoUpdater.ExitList.Add(this);
                    foreach (var i in _Children)
                    {
                        if (i is IUpdatable)
                        {
                            AutoUpdater.TaskList.Add(i as IUpdatable);
                        }
                    }
                    lock (AutoUpdater.TaskList) { Monitor.Pulse(AutoUpdater.TaskList); }
                });
            }
        }

        /// <summary>
        /// Get the array of web folder items. Because the ways get the array is different in root and in sub folder.
        /// </summary>
        /// <returns></returns>
        protected abstract WebFolderItemInfo[] GetItems();

        /// <summary>
        /// Begin get items.
        /// </summary>
        /// <param name="callBack"></param>
        /// <returns></returns>
        IAsyncResult BeginGetItems(AsyncCallback callBack)
        {
            AsyncReturnDelegate<WebFolderItemInfo[]> dele = () => GetItems();
            return dele.BeginInvoke(callBack, dele);
        }

        /// <summary>
        /// End the call of the BeginGetItem();
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        WebFolderItemInfo[] EndGetItems(IAsyncResult result)
        {
            return ((AsyncReturnDelegate<WebFolderItemInfo[]>)result.AsyncState).EndInvoke(result);
        }

        #region Updatable Members

        /// <summary>
        /// Get the children of this collection.
        /// </summary>
        public void Update() { TryGetChildren(); }

        #endregion
    }
}
